<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>策略模式</title>
  </head>
  <body>
    <form action="http:// xxx.com/register" id="registerForm" method="post">
      <span>请输入用户名：</span><input type="text" name="userName"/ > 请输入密码：<input type="text" name="password"/ >
      请输入手机号码：<input type="text" name="phoneNumber"/ >
      <button>提交</button>
    </form>
    <script>
      // const Maps = new Map([
      //   [
      //     'S',
      //     function (salary) {
      //       return salary * 4;
      //     },
      //   ],
      //   [
      //     'A',
      //     function (salary) {
      //       return salary * 3;
      //     },
      //   ],
      //   [
      //     'B',
      //     function (salary) {
      //       return salary * 2;
      //     },
      //   ],
      // ]);

      /**
       * 第一步我们要把这些逻辑都封装成策略对象：
       */
      const strategies = {
        S: function (salary) {
          return salary * 4;
        },
        A: function (salary) {
          return salary * 3;
        },
        B: function (salary) {
          return salary * 2;
        },
      };
      // console.log('Maps', Maps.get('S'));
      const calculateBonus = function (level, salary) {
        return strategies[level](salary);
      };

      class GradeA {
        computed(bonus) {
          return bonus * 3;
        }
      }

      class GradeB {
        computed(bonus) {
          return bonus * 2;
        }
      }

      class ComputedBonus {
        constructor(salary, strategy) {
          this.salary = salary;
          this.strategy = strategy;
        }
        getBonus() {
          return this.strategy.computed(this.salary);
        }
      }

      const computedBonus1 = new ComputedBonus(3000, new GradeS());
      const computedBonus2 = new ComputedBonus(2000, new GradeA());

      console.log(computedBonus1.getBonus()); // 12000
      console.log(computedBonus2.getBonus()); // 6000

      /**
       * 策略类往往被函数所代替，这时策略模式就成为一种“隐形”的模式
       */
      const Sa = function (salary) {
        return salary * 4;
      };
      const Aa = function (salary) {
        return salary * 3;
      };
      const Ba = function (salary) {
        return salary * 2;
      };
      const calculateBonusa = function (func, salary) {
        return func(salary);
      };
      calculateBonusa(Sa, 10000); // 输出：40000

      /**
       * 策略模式应用
       */
      // ==========表单校验==========
      const registerFormDom = document.getElementById('registerForm');
      // console.log('registerFormDom', registerFormDom);
      // console.log(registerFormDom.userName);
      // console.log(registerFormDom.password);
      registerFormDom.onsubmit = function (e) {
        const errorMsg = validataFunc(); // 如果 errorMsg 有确切的返回值，说明未通过校验
        if (errorMsg) {
          alert(errorMsg);
          return false; // 阻止表单提交
        }
      };

      const strategiess = {
        isNonEmpty: function (value, errorMsg) {
          if (value === '') {
            return errorMsg;
          }
        },
        minLength: function (value, length, errorMsg) {
          if (value.length < length) {
            return errorMsg;
          }
        },
        isMobile: function (value, errorMsg) {
          if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
            return errorMsg;
          }
        },
      };

      class Validator {
        cacheFn = []; // 保存校验规则函数
        // 添加规则
        addRule(dom, rule, errorMsg) {
          const args = rule.split(':'); // 把 strategy 和参数分开 ['minLength', '6']
          // 把校验的步骤用空函数包装起来，并且放入 cacheFn
          this.cacheFn.push(function () {
            const strategy = args.shift(); // 用户挑选的 strategy  'minLength'
            args.unshift(dom.value); // 把 input 的 value 添加进参数列表 [value,6]
            args.push(errorMsg); // 把 errorMsg 添加进参数列表 [value,6,errorMsg]
            return strategiess[strategy].call(dom, ...args);
          });
        }
        // 开始验证
        start() {
          for (let i = 0, len = this.cacheFn.length; i < len; i++) {
            const msg = validatorFunc(); // 开始校验，并取得校验后的返回信息
            // 如果有确切的返回值，说明校验没有通过
            if (msg) return msg;
          }
          return false;
        }
      }

      const validataFunc = function () {
        const validator = new Validator(); // 创建一个 validator 对象
        /***************添加一些校验规则****************/
        validator.add(registerFormDom.userName, 'isNonEmpty', '用户名不能为空');
        validator.add(registerFormDom.password, 'minLength:6', '密码长度不能少于 6 位');
        validator.add(registerFormDom.phoneNumber, 'isMobile', '手机号码格式不正确');
        const errorMsg = validator.start(); // 获得校验结果
        return errorMsg; // 返回校验结果
      };
    </script>
  </body>
</html>
